import 'dart:async';
import 'dart:convert';
import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:state_manage/infinite_list/post.dart';
import './bloc.dart';
import 'package:http/http.dart' as Http;
import 'package:rxdart/rxdart.dart';

/// 永动列表 Bloc
class InfiniteBloc extends Bloc<InfiniteEvent, InfiniteState> {
  /// 网络请求工具
  final Http.Client httpClient;

  InfiniteBloc({@required this.httpClient});

  @override
  InfiniteState get initialState => PostUninitialized();

  @override
  Stream<InfiniteState> mapEventToState(
    InfiniteEvent event,
  ) async* {
    // 当前状态
    final currentState = state;

    /// 判断状态
    if (event is Fetch && !_hasReachMax(currentState)) {
      try {
        if (currentState is PostUninitialized) {
          // 加载数据
          final posts = await _fetchPosts(0, 20);
          yield PostLoaded(posts: posts, hasReachedMax: false);
        } else if (currentState is PostLoaded) {
          // 加载数据
          final posts = await _fetchPosts(currentState.posts.length, 20);
          yield posts.isEmpty
              ? currentState.copyWith(hasReachedMax: true)
              : PostLoaded(
                  posts: currentState.posts + posts, hasReachedMax: false);
        }
      } catch (_) {
        yield PostError();
      }
    }
  }

  /// 是否还有更多数据
  bool _hasReachMax(InfiniteState currentState) {
    if (state is PostLoaded) {
      return (state as PostLoaded).hasReachedMax;
    } else {
      return false;
    }
  }

  /// 加载数据
  Future<List<Post>> _fetchPosts(int startIndex, int limit) async {
    // 获取数据
    final response = await httpClient.get('https://jsonplaceholder.typicode.com/posts?_start=$startIndex&_limit=$limit');
    // 检测状态码
    if (response.statusCode == 200) {
      final data = json.decode(response.body) as List;
      return data.map((rawPost) {
        return Post(
          id: rawPost['id'],
          title: rawPost['title'],
          body: rawPost['body']
        );
      }).toList();
    } else {
      throw Exception('error fetching posts');
    }
  }

  // 设置事件间隔事件
  @override
  Stream<InfiniteState> transformEvents(Stream<InfiniteEvent> events, Stream<InfiniteState> Function(InfiniteEvent event) next) {
    return super.transformEvents((events as Observable<InfiniteEvent>).debounceTime(Duration(milliseconds: 500)), next);
  }
}
